#include "copyright.h"

#include "syscall.h"
#include "ConcessionClerk.h"


void finishedAgent(const char* name, int length){

	if(GetMonitor(ManagerFinishedName, ManagerFinishedNameLength, 0) == 1){
		ReleaseLock(name, length);
		Exit(1);
	}

}


int concessionClerkInitialize(){

	int myIndex;
	
	AcquireLock(concessionClerkIndexLockName, concessionClerkIndexLockNameLength);
		myIndex = GetMonitor(nextConcessionClerkName, nextConcessionClerkNameLength,0);
		SetMonitor(nextConcessionClerkName, nextConcessionClerkNameLength, myIndex + 1,0);
	ReleaseLock(concessionClerkIndexLockName, concessionClerkIndexLockNameLength);

	SetMonitor(concessionClerkLineCountName, concessionClerkLineCountNameLength, 0, myIndex);
	SetMonitor(concessionClerkStateName, concessionClerkStateNameLength, -1, myIndex);
				
	return myIndex;

}

void concessionClerk(){
	
	int myIndex;
	int tmp;
	
	myIndex = concessionClerkInitialize();
	
	while(1){ 
	/* while true */
		/*Printing("ConcessionClerk %i\n", ConsoleOutput, myIndex, 0);*/
		AcquireLock(concessionClerkLineLockName, concessionClerkLineLockNameLength); /* Lock for choosing a line */
		/* check if there is a customer in my line */
		if(GetMonitor(concessionClerkLineCountName,concessionClerkLineCountNameLength,myIndex) > 0){ /* There is someone in my line */
			/*printf("\t\tCC%i: Someone is in my line!\n", myIndex);*/
			/* Steps
			1. set my state to busy
			2. decrement line count
			3. wake up 1 customer */
			
			Printing("ConcessionClerk %i has a line length %i and is signaling a customer.\n", ConsoleOutput, myIndex, GetMonitor(concessionClerkLineCountName,concessionClerkLineCountNameLength,myIndex));
			SetMonitor(concessionClerkStateName, concessionClerkStateNameLength, 1, myIndex);
			/*concessionClerkState[myIndex] = 1;  state = BUSY */
			SetMonitor(concessionClerkLineCountName, concessionClerkLineCountNameLength, GetMonitor(concessionClerkLineCountName, concessionClerkLineCountNameLength, myIndex) - 1, myIndex);
			/*concessionClerkLineCount[myIndex]--;  decrement line count */
			Signal(concessionClerkLineConditionVariableName[myIndex], concessionClerkLineConditionVariableNameLength[myIndex], concessionClerkLineLockName, concessionClerkLineLockNameLength);
		} else { /* no one is in my line */
			/* Steps
			1. set my state to not_busy */
			Printing("ConcessionClerk %i has no one in line. I am available for a customer.\n", ConsoleOutput, myIndex, 0);
			
			SetMonitor(concessionClerkStateName, concessionClerkStateNameLength, 0, myIndex);
			/*concessionClerkState[myIndex] = 0;  state = NOT_BUSY */
		}
		
		/* done with concession clerks first monitor.
		   concession clerk is ready to wait
		   by acquiring the next lock before releasing the current lock,
		   we guarantee that we get the lock first */
		
		AcquireLock(concessionClerkLockName[myIndex], concessionClerkLockNameLength[myIndex]);  
		ReleaseLock(concessionClerkLineLockName, concessionClerkLineLockNameLength);
		
		/*STEP 1: ConcessionClerk-Customer, Waiting for the customer to come up to the counter.*/
		/*printf("\t\tCC%i: Waiting for the customer to walk on up here!\n", myIndex);*/
		Wait(concessionClerkConditionVariableName[myIndex], concessionClerkConditionVariableNameLength[myIndex], concessionClerkLockName[myIndex], concessionClerkLockNameLength[myIndex]);
		finishedAgent(concessionClerkLockName[myIndex], concessionClerkLockNameLength[myIndex]);
		
		if(GetMonitor(concessionClerkStateName, concessionClerkStateNameLength, myIndex) != 0){
			/*STEP 2: ConcessionClerk-Customer, Tells customer the total*/
			
			Printing("ConcessionClerk %i has an order for %i popcorn \0", ConsoleOutput, myIndex, GetMonitor(concessionClerkPopcornToSellName, concessionClerkPopcornToSellNameLength,myIndex));
			Printing("and %i soda. The cost is %i.\n", ConsoleOutput, GetMonitor(concessionClerkSodaToSellName,concessionClerkSodaToSellNameLength,myIndex), (GetMonitor(concessionClerkPopcornToSellName, concessionClerkPopcornToSellNameLength,myIndex)*5 + GetMonitor(concessionClerkSodaToSellName, concessionClerkSodaToSellNameLength,myIndex)*4));

			Signal(concessionClerkConditionVariableName[myIndex], concessionClerkConditionVariableNameLength[myIndex], concessionClerkLockName[myIndex], concessionClerkLockNameLength[myIndex]);
			Wait(concessionClerkConditionVariableName[myIndex], concessionClerkConditionVariableNameLength[myIndex], concessionClerkLockName[myIndex], concessionClerkLockNameLength[myIndex]);
			finishedAgent(concessionClerkLockName[myIndex], concessionClerkLockNameLength[myIndex]);
			
			/*STEP 3: ConcessionClerk-Customer, Takes cash from customer.*/
			tmp = (GetMonitor(concessionClerkPopcornToSellName, concessionClerkPopcornToSellNameLength,myIndex)*5 + GetMonitor(concessionClerkSodaToSellName, concessionClerkSodaToSellNameLength,myIndex)*4);
			SetMonitor(concessionClerkRegisterName, concessionClerkRegisterNameLength, GetMonitor(concessionClerkRegisterName, concessionClerkRegisterNameLength, myIndex) + tmp ,myIndex);
			/*concessionClerkRegister[myIndex] += (concessionClerkPopcornToSell[myIndex]*5 + concessionClerkSodaToSell[myIndex]*4);*/
			Printing("ConcessionClerk %i has been paid for the order.\n", ConsoleOutput, myIndex, 0);

			SetMonitor(concessionClerkPopcornToSellName, concessionClerkPopcornToSellNameLength, 0, myIndex);
			SetMonitor(concessionClerkSodaToSellName, concessionClerkSodaToSellNameLength,0,myIndex);
			
			Signal(concessionClerkConditionVariableName[myIndex], concessionClerkConditionVariableNameLength[myIndex], concessionClerkLockName[myIndex], concessionClerkLockNameLength[myIndex]);
			Wait(concessionClerkConditionVariableName[myIndex], concessionClerkConditionVariableNameLength[myIndex], concessionClerkLockName[myIndex], concessionClerkLockNameLength[myIndex]);
			finishedAgent(concessionClerkLockName[myIndex], concessionClerkLockNameLength[myIndex]);
		}
		
		AcquireLock(concessionClerkBreakLockName[myIndex], concessionClerkBreakLockNameLength[myIndex]);
		
		ReleaseLock(concessionClerkLockName[myIndex], concessionClerkLockNameLength[myIndex]);
		
		if(GetMonitor(concessionClerkBreakName,concessionClerkBreakNameLength,myIndex) == 1){ /* i should go on break */
			Printing("ConcessionClerk %i is going on break.\n", ConsoleOutput, myIndex, 0);
			/*AcquireLock(concessionClerkLineLock);*/
			/*concessionClerkLineCount[myIndex] = 0;*/
			/*Broadcast(concessionClerkLineConditionVariable[myIndex], concessionClerkLineLock);*/ /* signal to everyone in my line. need to acquire first???? */
			/*ReleaseLock(concessionClerkLineLock);*/
			Wait(concessionClerkBreakConditionVariableName[myIndex],concessionClerkBreakConditionVariableNameLength[myIndex],  concessionClerkBreakLockName[myIndex], concessionClerkBreakLockNameLength[myIndex]); /* wait until I am off break */
			finishedAgent(concessionClerkBreakLockName[myIndex], concessionClerkBreakLockNameLength[myIndex]);
			Printing("ConcessionClerk %i is coming off break.\n", ConsoleOutput, myIndex, 0);
		}

		ReleaseLock(concessionClerkBreakLockName[myIndex], concessionClerkBreakLockNameLength[myIndex]);
	}
	
}


int main(){

	concessionClerk();

Exit(1);
}